const { ccclass, property } = cc._decorator;
@ccclass
export default class MaskPlus extends cc.Mask {
    @property({
        type: cc.Enum({
            RECT: 0,
            ELLIPSE: 1,
            IMAGE_STENCIL: 2,
            POLYGON: 3
        }),
        override: true
    })
    private _type: number = 0;

    @property({
        type: [cc.Vec2],
        serializable: true
    })
    private _polygon: cc.Vec2[] = [];

    public onLoad() {
        this._activateMaterial();
        this._updateGraphics();
    }

    public set type(value: number) {
        if (this._type !== value) {
            this._resetAssembler();
        }
        this._type = value;
        if (this._type === 3 && this._polygon.length === 0) {
            let rect = this.getNodeRect();
            let [x, y, width, height] = rect;
            this._polygon.push(cc.v2(x, y), cc.v2(x + width, y), cc.v2(x + width, y + height), cc.v2(x, y + height));
        }
        if (this._type !== 2) {
            this.spriteFrame = null;
            this.alphaThreshold = 0;
            this._updateGraphics();
        }
    }

    public get type(): number {
        return this._type;
    }

    @property({
        type: [cc.Vec2],
        override: true
    })
    public set polygon(value: cc.Vec2[]) {
        this._polygon = value;
        this._updateGraphics();
    }

    public get polygon(): cc.Vec2[] {
        return this._polygon;
    }

    public setEllipse(center: cc.Vec2, radius: cc.Vec2, segments?: number) {
        this._type = 1;
        this._polygon = [];
        this.ellipse.center = center;
        this.ellipse.radius = radius;
        this.ellipse.segments = segments || this.segments;
        this._updateGraphics();
    }

    private _updateGraphics() {
        let graphics = this._graphics;
        if (graphics) {
            graphics.clear(false);
            let rect = this.getNodeRect();
            let [x, y, width, height] = rect;
            if (this._type === 0) {
                graphics.rect(x, y, width, height);
            } else if (this._type === 1) {
                let ellipse = this.ellipse;
                let vertexes = this._calculateEllipseVertices(ellipse.center || cc.v2(x + width / 2, y + height / 2), ellipse.radius || cc.v2(width / 2, height / 2), ellipse.segments || this.segments);
                for (let i = 0; i < vertexes.length; ++i) {
                    let vertex = vertexes[i];
                    if (i === 0) {
                        graphics.moveTo(vertex.x, vertex.y);
                    } else {
                        graphics.lineTo(vertex.x, vertex.y);
                    }
                }
                graphics.close();
            } else if (this._type === 3) {
                if (this._polygon.length === 0) {
                    this._polygon.push(cc.v2(0, 0));
                }
                graphics.moveTo(this._polygon[0].x, this._polygon[0].y);
                for (let i = 1; i < this._polygon.length; i++) {
                    graphics.lineTo(this._polygon[i].x, this._polygon[i].y);
                }
                graphics.lineTo(this._polygon[0].x, this._polygon[0].y);
            }
            if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
                graphics.stroke();
            } else {
                graphics.fill();
            }
        }
    }

    private _hitTest() {
        return true;
    }

    private getNodeRect() {
        let width = this.node._contentSize.width;
        let height = this.node._contentSize.height;
        return [-width * this.node._anchorPoint.x, -height * this.node._anchorPoint.y, width, height];
    }

    public setPolygonArray(polygon: cc.Vec2[]) {
        this.polygon = polygon;
    }

    private _calculateEllipseVertices(center: cc.Vec2, radius: cc.Vec2, segments: number) {
        let vertices = [];
        let angleStep = 2 * Math.PI / segments;
        for (let i = 0; i < segments; ++i) {
            vertices.push(cc.v2(radius.x * Math.cos(angleStep * i) + center.x, radius.y * Math.sin(angleStep * i) + center.y));
        }
        return vertices;
    }
}
